#ifndef __CANYON_LIB_BIT
#define __CANYON_LIB_BIT

#include <cstdint>
#include <stdexcept>

namespace canyon{

template<typename T>
class BitPointer;

template<typename T=uint8_t>
class Bit{
    protected:
    BitPointer<T> *pointer_obj;
    size_t         index;
    public:

    Bit(BitPointer<T> * pointer, size_t index){
        this->pointer_obj = pointer;
        this->index       = index;
    }

    operator bool(){
        return this->pointer_obj->get(this->index);
    }

    void operator=(bool value){
        this->pointer_obj->set(this->index, value);
    }
};

template<typename T=uint8_t>
class BitPointer{
    protected:

    static void verify_index(size_t index){
        if(index>=sizeof(T)*8){
            throw std::out_of_range("BitPointer: index out of range");
        }
    }

    public:
    T * pointer;

    public:

    BitPointer(T & data){
        this->pointer = &data;
    }

    BitPointer(T * pointer){
        this->pointer = pointer;
    }

    bool get(size_t index){
        BitPointer<T>::verify_index(index);
        T operat = 1<<(T)index;
        return (*(this->pointer))&operat;
    }

    void set(size_t index, bool value){
        BitPointer<T>::verify_index(index);
        if(this->get(index)!=value){
            T tmp    = *(this->pointer);
            T operat = 1<<(T)index;
            if(value){
                tmp |= operat;
            } else {
                operat = ~operat;
                tmp    = tmp&operat;
            }
            *(this->pointer) = tmp;
        }
    }

    Bit<T> at(size_t index){
        BitPointer::verify_index(index);
        return Bit<T>(this, index);
    }

    Bit<T> operator[](size_t index){
        return this->at(index);
    }
};

}

#endif
